package com.totem.base.util;

import java.time.DayOfWeek;
import java.time.Instant;
import java.time.LocalDate;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 节假日, 需要每年年底配置下一年的数据
 */
public class HolidayHelper {
    // 当前年份
    private int year = 2020;
    // 元旦节
    private List<String> newYear = List.of("01-01");
    private List<String> newYearWork = List.of();
    // 春节
    private List<String> spring = List.of("01-24", "01-25", "01-26", "01-27", "01-28", "01-29", "01-30", "01-31", "02-01", "02-02");
    private List<String> springWork = List.of("01-19");
    // 清明节
    private List<String> tombSweeping = List.of("04-04", "04-05", "04-06");
    private List<String> tombSweepingWork = List.of();
    // 劳动节
    private List<String> labour = List.of("05-01", "05-02", "05-03", "05-04", "05-05");
    private List<String> labourWork = List.of("04-26", "05-09");
    // 端午节
    private List<String> dragonBoat = List.of("06-25", "06-26", "06-27");
    private List<String> dragonBoatWork = List.of("06-28");
    // 中秋节
    private List<String> moon = List.of();
    private List<String> moonWork = List.of("09-27");
    // 国庆节
    private List<String> national = List.of("10-01", "10-02", "10-03", "10-04", "10-05", "10-06", "10-07", "10-08");
    private List<String> nationalWork = List.of("10-10");

    // 节日清单 dayOfYear
    private static List<Integer> festivalList = new ArrayList<>();
    // 因节假日调整的加班日清单 dayOfYear
    private static List<Integer> workExtraList = new ArrayList<>();
    // 节假日清单 dayOfYear
    private static List<Integer> holidayList = new ArrayList<>();

    private HolidayHelper(){
        init();
    }

    public void init(){
        // 输入参数: MM-dd
        Function<String, Integer> dayOfMonthToYear = monthDay->{
            String[] date = monthDay.split("-");
            String monthString = date[0];
            int month = Integer.valueOf(monthString);
            String dayOfMonthString = date[1];
            int dayOfMonth = Integer.valueOf(dayOfMonthString);
            LocalDate ld = LocalDate.of(year, month, dayOfMonth);
            return ld.getDayOfYear();
        };

        // 合并节日
        List<String> festivalStringList = new ArrayList<>();
        Stream.of(newYear, spring, tombSweeping, labour, dragonBoat, moon, national).forEach(festivalStringList::addAll);
        festivalList = festivalStringList.stream().map(dayOfMonthToYear).collect(Collectors.toList());

        // 合并调班
        List<String> workExtraStringList = new ArrayList<>();
        Stream.of(newYearWork, springWork, tombSweepingWork, labourWork, dragonBoatWork, moonWork, nationalWork).forEach(workExtraStringList::addAll);
        workExtraList = workExtraStringList.stream().map(dayOfMonthToYear).collect(Collectors.toList());

        LocalDate startDay = LocalDate.ofYearDay(year, 1);
        LocalDate endDay = startDay.withYear(year+1).minusDays(1);
        int endDayOfYear = endDay.getDayOfYear();
        for(int i=1; i<=endDayOfYear; i++){
            LocalDate ld = LocalDate.ofYearDay(year, i);
            DayOfWeek dow = ld.getDayOfWeek();
            int idow = dow.getValue();
            if((festivalList.contains(i) || idow==6 || idow==7) && !workExtraList.contains(i)){
                holidayList.add(i);
            }
        }
    }

    public boolean isHoliday(Date date){
        return isHoliday(timestampToLocalDate(date.getTime()).getDayOfYear());
    }

    public boolean isHoliday(int dayOfYear){
        return holidayList.contains(dayOfYear);
    }

    public LocalDate timestampToLocalDate(long timestamp){
        return Instant.ofEpochMilli(timestamp).atZone(ZoneOffset.ofHours(8)).toLocalDate();
    }

    public static HolidayHelper getInstance(){
        return HolidayHelperSingleton.holder;
    }

    private static class HolidayHelperSingleton {
        private static HolidayHelper holder = new HolidayHelper();
    }
}
